﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GameLib.Serialization
{
	class SerializerCollection : ICollection<Serializer>
	{
		public Serializer FindSerializerFor(Type type)
		{
			Serializer foundSerializer;

			if (TypeToSerializerCache.TryGetValue(type, out foundSerializer))
				return foundSerializer;

			foundSerializer = null;
			foreach (Serializer serializer in Serializers)
			{
				if (serializer.Support(type))
				{
					foundSerializer = serializer;
					break;
				}
			}

			//cache it
			TypeToSerializerCache[type] = foundSerializer;
			return foundSerializer;
		}

		#region ICollection<Serializer> Members

		public void Add(Serializer item)
		{
			Type newType = item.SupportedType;

			// insert at the location such that specific to general order is maintained
			int i = 0;
			for (; i < Serializers.Count; i++)
			{
				Type curType = Serializers[i].SupportedType;

				if (newType.IsSubclassOf(curType)) // insert at this location
					break;
				else if (newType == curType)
					throw new Exception(string.Format("Trying to add serializer {0} for type {1}, but there is already another one supporting for the same type", item.ToString(), newType.ToString()));
			}

			Serializers.Insert(i, item);
			ClearTypeToSerializerCache();
		}

		public void Clear()
		{
			Serializers.Clear();
			ClearTypeToSerializerCache();
		}

		public bool Contains(Serializer item)
		{
			return Serializers.Contains(item);
		}

		public void CopyTo(Serializer[] array, int arrayIndex)
		{
			Serializers.CopyTo(array, arrayIndex);
		}

		public int Count
		{
			get { return Serializers.Count; }
		}

		public bool IsReadOnly
		{
			get { return false; }
		}

		public bool Remove(Serializer item)
		{
			if (Serializers.Remove(item))
			{
				ClearTypeToSerializerCache();
				return true;
			}
			return false;
		}

		#endregion

		#region IEnumerable<Serializer> Members

		public IEnumerator<Serializer> GetEnumerator()
		{
			return Serializers.GetEnumerator();
		}

		#endregion

		#region IEnumerable Members

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}

		#endregion

		#region Private Functions

		private void ClearTypeToSerializerCache()
		{
			if (TypeToSerializerCache.Count > 0)
				TypeToSerializerCache.Clear();
		}

		#endregion

		#region Private Fields

		List<Serializer> Serializers = new List<Serializer>();
		Dictionary<Type, Serializer> TypeToSerializerCache = new Dictionary<Type, Serializer>();

		#endregion
	}
}
